package org.directfire.player.utils;

import org.directfire.player.model.Model;

import android.os.Parcel;
import android.os.Parcelable;

/**
 *   Copyright (C) 2012 Alexey Kostrjitskiy mailto:alex@ipss.net
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 * $Id: DFException.java 22 2012-08-27 06:00:54Z alexeyvk@gmail.com $<br/>
 * $HeadURL: http://directfire.googlecode.com/svn/trunk/DirectFireAndroid/src/org/directfire/player/utils/DFException.java $<br/><br/>
 *
 * DirectFirePlayer exception parcelable class for inter-thread messaging. 
 * 
 *  1хх 								Информационное сообщение:<br/>
 *  100 void							- действие не произведено<br/>  
 *  
 *  4хх 												Критические ошибки:<br/>
 *  401 multiplayer_exception			- com.spoledge.aacdecoder.MultiPlayer внутреняя ошибка <br/>
 *  402 remote_exception					- RemoteException при отправке сообщения сервису <br/>  
 *  */
public class DFException extends RuntimeException implements Parcelable{
	private static final long serialVersionUID = -6438849497295021920L;

	/** internal error code*/
	private int code;
	/** internal error name*/
	private String name;
	/** error description*/
	private String text;
	/** debug stack trace*/
	private String debug;

	/** @return internal error code  */ 
	public int getCode()  {return code;}
	/** @return internal error name  */	
	public String getName(){return name;}
	/** @return error text */	
	public String getText(){return text;}
	/** @return error stack trace */	
	public String getDebug(){return debug;}
	/** @return human readable error description */
	@Override
	public String toString() {
  	String ret=name+"("+code+")"+": "+text;
  	ret+= Model.getI().isDebug()?"\n"+debug:"";
    return ret;
	}

	/** @return error description in XML */
  public String toXMLString()
  {
  	String ret="<error name=\""+name+"\" code=\""+code+"\">\n\t<text>"+text+"</text>\n";
  	ret+=Model.getI().isDebug()?"\t<debug><![CDATA["+debug+"]]></debug>\n</error>":"</error>";
    return ret;
  }
  
  /************************************ Parcelable **************/
  /** for parcelable .*/
	public int describeContents() {
		return hashCode();
	}
	/** make error parcelable */
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeInt(code);
		dest.writeString(name);
		dest.writeString(text);
		dest.writeString(debug);
	}
	/** for parcelable */
	public class Creator implements Parcelable.Creator<DFException> {
		public DFException createFromParcel(Parcel source) {
			return new DFException(source);
		}
	  public DFException[] newArray(int size) {
	  	return new DFException[size];
	  }
	}
  /************************************ Parcelable **************/  
	
	/** Default constructor*/
	public DFException(){
		super();
		code = 0;
		name = "exception_unknown";
		text = "";
		debug= "";
	}
	
	/** Constructor for parcelable */
	public DFException(Parcel s){
		code = s.readInt();
		name = s.readString();
		text = s.readString();
		debug = s.readString();
	}
	
	/** Constructor for Exception object associated with internal error */
	public DFException(Exception e, int code)
	{
		super(e);
		parseCode(code);
		this.code = code;
		this.text = getCause().toString();
		this.debug = getDebugTrace(getCause());
	}

	/** Constructor for Exception object associated with internal error */
	public DFException(Throwable t, int code)
	{
		super(t);
		parseCode(code);
		this.code = code;
		this.text = getCause().toString();
		this.debug = getDebugTrace(getCause());
	}
	
	/** Constructor for internal error */	
	public DFException(int code, String text)
	{
		super();
		parseCode(code);
		this.code = code;
		this.text = text;
		this.debug = getDebugTrace(getCause());
	}
	
	/** parser for internal error names */
	private void parseCode(int code){
		switch(code){
		case 100:
			this.name="void";
			break;
		case 401:
			this.name="multiplayer_exception";
			break;
		case 402:
			this.name="remote_exception";
			break;
		default:
			this.name="exception_unknown";
		}
	}

	/** @return stack trace from Throwable */
  private String getDebugTrace(Throwable t)
  {
  	if(t==null)
  		return "";
  	StackTraceElement el = ((Exception)t).getStackTrace()[0];
  	String ret="at "+ el.getClassName()+"."+el.getMethodName()+"("+el.getFileName()+":"+el.getLineNumber()+")\n";
  	for(int i = 0 ; i < t.getStackTrace().length ; i++)
  		ret+=t.getStackTrace()[i]+"\n";
  	return ret;
  }
}
